﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using EnvDTE;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.TextManager.Interop;
using OleInterop = Microsoft.VisualStudio.OLE.Interop;
using System.ComponentModel.Composition;

namespace VsSpeakerCompanion
{
    /// <summary>
    /// Exposes core Visual Studio functionality
    /// </summary>
    /// <remarks>
    /// The only reason we need this is because we need to get to an IServiceProvider from a MEF component which isn't easily supported right now.
    /// In later releases of Visual Studio 2010 it may be possible to access an IServiceProvider from a MEF component and when that
    /// happens this code won't be needed anymore
    /// </remarks>
    public class VisualStudioHelper
    {
        private bool isInitialized;

        /// <summary>
        /// Gets the service provider used to get services from Visual Studio.
        /// </summary>
        public System.IServiceProvider ServiceProvider { get; private set; }

        internal VisualStudioHelper()
        { }

        /// <summary>
        /// Used to construct a helper. The textbuffer will provide the service provider.
        /// </summary>
        public VisualStudioHelper(ITextBuffer textBuffer)
        {
            Initialize(textBuffer);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000")]
        private static System.IServiceProvider GetServiceProviderFromTextBuffer(ITextBuffer textBuffer)
        {
            IObjectWithSite objectWithSite = textBuffer.Properties.GetProperty<IObjectWithSite>(typeof(IVsTextBuffer));
            if (objectWithSite != null)
            {
                Guid serviceProviderGuid = typeof(Microsoft.VisualStudio.OLE.Interop.IServiceProvider).GUID;
                IntPtr ppServiceProvider = IntPtr.Zero;
                // Get the service provider pointer using the Guid of the OleInterop ServiceProvider
                objectWithSite.GetSite(ref serviceProviderGuid, out ppServiceProvider);

                if (ppServiceProvider != IntPtr.Zero)
                {
                    // Create a System.ServiceProvider with the OleInterop ServiceProvider
                    OleInterop.IServiceProvider oleInteropServiceProvider = (OleInterop.IServiceProvider)Marshal.GetObjectForIUnknown(ppServiceProvider);
                    return new ServiceProvider(oleInteropServiceProvider);
                }
            }

            return null; 
        }

        /// <summary>
        /// Initializes the helper
        /// </summary>
        /// <param name="textBuffer"></param>
        internal void Initialize(ITextBuffer textBuffer)
        {
            if (!isInitialized)
            {
                this.ServiceProvider = GetServiceProviderFromTextBuffer(textBuffer);

                isInitialized = this.ServiceProvider != null;
            }
        }
    }
}